package com.atzly.community.quartz;

import com.atzly.community.constant.CommentConstant;
import com.atzly.community.entity.DiscussPost;
import com.atzly.community.service.DiscussPostService;
import com.atzly.community.service.ElastaticSearchService;
import com.atzly.community.service.LikeService;
import com.atzly.community.utils.RedisKeyUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 计算帖子分数的定时任务
 *
 * @author zlysimida
 * @date 2021/9/4 - 16:50
 */
@Component
public class CalculationPostScoreJob implements Job, CommentConstant {

    // 纪元节点
    private static final Date epoch;

    private static final Logger LOGGER = LoggerFactory.getLogger(CalculationPostScoreJob.class);

    static {
        try {
            epoch = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2014-08-01 00:00:00");
        } catch (ParseException e) {
            LOGGER.error("牛客纪元初始化失败!");
            throw new RuntimeException("初始化仿牛客纪元常量失败!");
        }
    }

    private static final long DAY = 1000 * 3600 * 24;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private DiscussPostService discussPostService;

    @Autowired
    private LikeService likeService;

    @Autowired
    private ElastaticSearchService elastaticSearchService;

    // 定时任务主要流程,每过三秒,从redis中获取存储的每个帖子(set存储每个帖子的id),如果redis中有帖子,那么就依次更新每个帖子,更新的具体内容为,首先更新数据库然后更新es中的当前post
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String postScoreKey = RedisKeyUtils.getPostScoreKey();
        // 获取操作该集合的对象
        BoundSetOperations operations = redisTemplate.boundSetOps(postScoreKey);

        if (operations.size() == 0) {
            LOGGER.info("任务取消,没有需要刷新的帖子");
            return;
        }

        LOGGER.info("任务开始！正在刷新帖子分数: " + operations.size());
        while (operations.size() > 0) {
            // set底层就是一个HashMap随机弹出一个贴子id
            this.refresh((Integer) operations.pop());
        }

        LOGGER.info("任务结束! 帖子分数刷新完毕!");
    }

    // 刷新帖子
    private void refresh(int postId) {
        DiscussPost post = discussPostService.selectDiscussDetails(postId);

        if (post == null) {
            LOGGER.error("该帖子不存在! id=" + postId);
            return;
        }

        // 是否精华
        boolean isWonderful = post.getStatus() == 1;
        // 评论数量
        Integer commentCount = post.getCommentCount();
        // 点赞数量
        long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, postId);

        // 根据公式log((wonderful ? 75 : 0) + commentCount * 10 + likeCount * 2) + (帖子创建时间 - 牛客创建时间) / 天数
        double w = (isWonderful ? 75 : 0) + commentCount * 10 + likeCount * 2;
        double score = Math.log10(Math.max(w, 1)) + (post.getCreateTime().getTime() - epoch.getTime()) / DAY;

        // 更新数据库
        discussPostService.updateDiscussPostScore(postId, score);

        // 更新es
        post.setScore(score);
        elastaticSearchService.addEntityToEs(post);
    }
}
